﻿// =====================================================================
// World.cs
// by Hushel Roberts
// =====================================================================

//#define DEBUG_MODE      // Defining enables graphic debugging for sprites
//#define DEBUG_CONTROLS  // Defining enables debugging for UI


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using Tank;
using MathUtil;
using Physics;
using Geometry;

namespace Tank
{
    public sealed class World
    {
        private static volatile World instance;
        private static object syncRoot = new Object();

        Rectangle worldSize;
        public List<Sprite> spriteList; // TODO
        List<Player> playerList;
        public Level currLevel;
        Dictionary<string, Texture2D> textureMap;
        SpriteBatch spriteBatch;
        Dictionary<string, SpriteFont> fontList;

        bool gameOver = false;

		HUD hud;
        private World() 
        {
        }

        public static World Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (syncRoot)
                    {
                        if (instance == null)
                            instance = new World();
                    }
                }
                return instance;
            }
        }

        //=============================================================
        // InitWorld
        // Desc: Initializes the world
        //=============================================================
        public void InitWorld(Rectangle playable, Rectangle _worldSize, SpriteBatch _spriteBatch)
        {
            // Create new level            
            currLevel = new Level(mapTheme.Tron, playable, _worldSize);

            // Initialize Game states
            worldSize = _worldSize;
            spriteBatch = _spriteBatch;

            spriteList = new List<Sprite>();
        }

        //=============================================================
        // InitSprites
        // Desc: Loads all variables for every sprite in the world
        //=============================================================
        private void InitSprites()
        {
            // Initialize sprites for Level - Use ResetLevel ( calls currLevel.Initialize )
            currLevel.ResetLevel();


        }

        //=============================================================
        // AddSprite
        //Desc: Adds sprites to be drawn
        //=============================================================
        public void AddSprite(Sprite sprite)
        {
            Debug.Assert(sprite != null);
            spriteList.Add(sprite);
        }

        //=============================================================
        // DestroySprites
        //Desc: Adds sprites to be drawn
        //=============================================================
        public void ResetWorld()
        {
            if (spriteList != null)
                spriteList = new List<Sprite>();

            InitSprites();
        }

        //=============================================================
        // SetPlayers
        //Desc: Sets the players to be updated and drawn in the world
        //=============================================================
        public void SetPlayers(List<Player> currPlayerList, string[] tankSelectionArray)
        {
            Debug.Assert(currPlayerList != null);
            
			Debug.Assert(currPlayerList.Count > 0);
            Debug.Assert(tankSelectionArray != null);
            Debug.Assert(tankSelectionArray.Length == 4);

            playerList = currPlayerList;
            CreateTanks(tankSelectionArray);
        }


        //=============================================================
        // CreateTanks
        //Desc: Creates all player tank sprites
        //=============================================================
        public void CreateTanks(string[] tankSelectionArray)
        {
            Debug.Assert(tankSelectionArray != null);
            Debug.Assert(tankSelectionArray.Length == 4);

            foreach (Player player in playerList)
            {
                string choice = tankSelectionArray[(int)player.PlayerIndexID];

                int health = 100;
                uint damage = 20;
                float maxVel = 100;
                float maxAccel = 100;
                float defense = 7;
                float bonus = 1.33333f;
                float degrade = 0.66667f;
                float radius = 27.0f;
                float drawScale = 0.2f;
                int maxAmmo = -1;

                string colorStr;
                if (player.PlayerColor == Color.Red)
                    colorStr = "RedBases";
                else if (player.PlayerColor == Color.Green)
                    colorStr = "GreenBases";
                else if (player.PlayerColor == Color.Yellow)
                    colorStr = "YellowBases";
                else
                    colorStr = "BlueBases";

                // Desert Tank
                if (choice == "tank1")
                {       
                    // Tank1
                    float rotSpeed = 0.03f;
                    TankSprite tankSprite = new TankSprite(currLevel.GetSpawnPoint(), maxVel, maxAccel,
                                                            new Vector2(0, -1), 0.8f, colorStr, "tank1",
                                                            radius, health, (uint)defense, rotSpeed);
                    Turret turret = new Turret(new Vector2(200, 300), 100, 100, new Vector2(0, -1), colorStr, "turret",
                                                new Vector2(80, 29), 200.0f, 0, rotSpeed, maxAmmo, damage, tankSprite);
                    // Turret Animation
                    Animation turretAnim = new Animation(turret.TextureID, .25f, 1, 117, 385, 70, 1254, Animation.PlayDirection.FORWARD);
                    turret.AddAnimation(turretAnim, AnimationMode.STOP);
                    turret.Origin = new Vector2(59, 301);

                    tankSprite.SetTurret(turret);
                    tankSprite.DrawScale = drawScale;
                    turret.DrawScale = drawScale;
                    player.SetTank(tankSprite);

                    spriteList.Add(tankSprite);
                }
                else if (choice == "tank2")
                {      
                    // Tank2
                    float rotSpeed = 0.03f;
                    TankSprite tankSprite = new TankSprite(currLevel.GetSpawnPoint(), maxVel * bonus, maxAccel * bonus,
                                                            new Vector2(0, -1), 0.8f, colorStr, "tank2",
                                                            radius, health, (uint)(defense * degrade), rotSpeed);
                    Turret turret = new Turret(new Vector2(200, 300), 100, 100, new Vector2(0, -1), colorStr, "turret",
                                                new Vector2(80, 29), 200.0f, 0, rotSpeed, maxAmmo, damage, tankSprite);
                    // Turret Animation
                    Animation turretAnim = new Animation(turret.TextureID, .25f, 1, 134, 410, 366, 1222, Animation.PlayDirection.FORWARD);
                    turret.AddAnimation(turretAnim, AnimationMode.STOP);
                    turret.Origin = new Vector2(68, 331);
                    tankSprite.DrawScale = drawScale;
                    turret.DrawScale = drawScale;

                    tankSprite.SetTurret(turret);
                    player.SetTank(tankSprite);
                    spriteList.Add(tankSprite);
                }
                else if (choice == "tank3")
                {
                    // Tank3
                    float rotSpeed = 0.03f;
                    TankSprite tankSprite = new TankSprite(currLevel.GetSpawnPoint(), maxVel, maxAccel,
                                                            new Vector2(0, -1), 0.8f, colorStr, "tank3",
                                                            radius, health, (uint)(defense * bonus), rotSpeed);
                    Turret turret = new Turret(new Vector2(200, 300), 100, 100, new Vector2(0, -1), colorStr, "turret",
                                                new Vector2(80, 29), 200.0f, 0, rotSpeed, maxAmmo, (uint)(damage * degrade), tankSprite);
                    // Turret Animation
                    Animation turretAnim = new Animation(turret.TextureID, .25f, 1, 140, 406, 668, 1235, Animation.PlayDirection.FORWARD);
                    turret.AddAnimation(turretAnim, AnimationMode.STOP);
                    turret.Origin = new Vector2(71, 332);
                    tankSprite.DrawScale = drawScale;
                    turret.DrawScale = drawScale;

                    tankSprite.SetTurret(turret);
                    player.SetTank(tankSprite);
                    spriteList.Add(tankSprite);
                }
                if (choice == "tank4")
                {
                    // Tank4
                    float rotSpeed = 0.03f;
                    TankSprite tankSprite = new TankSprite(currLevel.GetSpawnPoint(), maxVel, maxAccel,
                                                            new Vector2(0, -1), 0.8f, colorStr, "tank4",
                                                            radius, health, (uint)(defense * degrade), rotSpeed);
                    Turret turret = new Turret(new Vector2(200, 300), 100, 100, new Vector2(0, -1), colorStr, "turret",
                                                new Vector2(80, 29), 200.0f, 0, rotSpeed, maxAmmo, (uint)(damage * bonus), tankSprite);
                    // Turret Animation
                    Animation turretAnim = new Animation(turret.TextureID, .25f, 1, 128, 429, 971, 1218, Animation.PlayDirection.FORWARD);
                    turret.AddAnimation(turretAnim, AnimationMode.STOP);
                    turret.Origin = new Vector2(65, 351);
                    tankSprite.DrawScale = drawScale;
                    turret.DrawScale = drawScale;

                    tankSprite.SetTurret(turret);
                    player.SetTank(tankSprite);
                    spriteList.Add(tankSprite);
                }

            }

            LoadAnimations();
        }


        //=============================================================
        // LoadAnimations
        // Desc: Loads Animations for sprite objects
        //=============================================================
        private void LoadAnimations()
        {
            foreach (Sprite sprt in spriteList)
            {
                Type t = Type.GetType("Tank.TankSprite");
                Type s = sprt.GetType();
                if (sprt.GetType() == Type.GetType("Tank.TankSprite")) 
                {
                    if(sprt.Name == "tank1")
                    {
                        // Forward treds
                        Animation tankForward = new Animation(((TankSprite)sprt).TextureID, .25f, 3, 256, 285, 0, 5, Animation.PlayDirection.REVERSE);
                        tankForward.SetFrame(1, 0, 470, 256, 285);
                        tankForward.SetFrame(2, 0, 934, 256, 285);
                        ((TankSprite)sprt).AddAnimation(tankForward, AnimationMode.BACKWARD);
                    }
                    else if(sprt.Name == "tank2")
                    {
                        // Forward treds
                        Animation tankForward = new Animation(((TankSprite)sprt).TextureID, .25f, 3, 256, 285, 304, 5, Animation.PlayDirection.REVERSE);
                        tankForward.SetFrame(1, 304, 470, 256, 285);
                        tankForward.SetFrame(2, 304, 934, 256, 285);
                        ((TankSprite)sprt).AddAnimation(tankForward, AnimationMode.BACKWARD);
                    }
                    else if(sprt.Name == "tank3")
                    {
                        // Forward treds
                        Animation tankForward = new Animation(((TankSprite)sprt).TextureID, .25f, 3, 256, 285, 609, 5, Animation.PlayDirection.REVERSE);
                        tankForward.SetFrame(1, 609, 470, 256, 285);
                        tankForward.SetFrame(2, 609, 934, 256, 285);
                        ((TankSprite)sprt).AddAnimation(tankForward, AnimationMode.BACKWARD);
                    }
                    else if(sprt.Name == "tank4")
                    {
                        // Forward treds
                        Animation tankForward = new Animation(((TankSprite)sprt).TextureID, .25f, 3, 256, 285, 915, 5, Animation.PlayDirection.REVERSE);
                        tankForward.SetFrame(1, 915, 470, 256, 285);
                        tankForward.SetFrame(2, 915, 934, 256, 285);
                        ((TankSprite)sprt).AddAnimation(tankForward, AnimationMode.BACKWARD);
                    }
                    
                }

            }

        }


        //=============================================================
        // InitTextures
        // Desc: Loads the artwork for all grphics into ContentManager
        //=============================================================
        public void InitTextures(SpriteBatch sb, ContentManager Content)
        {
            spriteBatch = sb;

            textureMap = new Dictionary<string, Texture2D>();
            textureMap.Add("breakdown", Content.Load<Texture2D>("breakdown"));
            textureMap.Add("particle", Content.Load<Texture2D>("particle"));
            textureMap.Add("dust", Content.Load<Texture2D>("dust"));
            textureMap.Add("SetupScreen", Content.Load<Texture2D>("SetupScreen"));
            textureMap.Add("The-Mainframe", Content.Load<Texture2D>("The-Mainframe"));
            textureMap.Add("New-Tron", Content.Load<Texture2D>("New-Tron"));
            textureMap.Add("TronBase", Content.Load<Texture2D>("TronBase"));
            textureMap.Add("TronTerrain", Content.Load<Texture2D>("TronTerrain"));
            textureMap.Add("SquareObject", Content.Load<Texture2D>("SquareObject"));
            textureMap.Add("DebugCircle", Content.Load<Texture2D>("DebugCircle"));
            textureMap.Add("Tanks", Content.Load<Texture2D>("Tanks"));
            textureMap.Add("BlueBases", Content.Load<Texture2D>("BlueBases"));
            textureMap.Add("GreenBases", Content.Load<Texture2D>("GreenBases"));
            textureMap.Add("RedBases", Content.Load<Texture2D>("RedBases"));
            textureMap.Add("YellowBases", Content.Load<Texture2D>("YellowBases"));
            
            textureMap.Add("ResultsScreen", Content.Load<Texture2D>("ResultsScreen"));
            textureMap.Add("ResultsButtons", Content.Load<Texture2D>("ResultsButtons"));
            textureMap.Add("Sky_01", Content.Load<Texture2D>("Sky_01"));
            textureMap.Add("Sky_02", Content.Load<Texture2D>("Sky_02"));
            textureMap.Add("Sky_03", Content.Load<Texture2D>("Sky_03"));
            textureMap.Add("Mountains_01", Content.Load<Texture2D>("Mountains_01"));
            textureMap.Add("Mountains_02", Content.Load<Texture2D>("Mountains_02"));
            textureMap.Add("Mountains_03", Content.Load<Texture2D>("Mountains_03"));
            textureMap.Add("GrassLoop", Content.Load<Texture2D>("GrassLoop"));
            textureMap.Add("GrassLoop_02", Content.Load<Texture2D>("GrassLoop"));
            textureMap.Add("MainScreenTank", Content.Load<Texture2D>("MainScreenTank"));
            textureMap.Add("TankdTitle", Content.Load<Texture2D>("TankdTitle"));

            textureMap.Add("PlasmaBlast", Content.Load<Texture2D>("PlasmaBlast"));
            textureMap.Add("New-Plasma-Shot", Content.Load<Texture2D>("New-Plasma-Shot"));

            textureMap.Add("Plasma", Content.Load<Texture2D>("Plasma"));
            textureMap.Add("Electro", Content.Load<Texture2D>("Electro"));

			textureMap.Add("HUDBackground", Content.Load<Texture2D>("HUDBackground"));
            //  Font
            fontList = new Dictionary<string, SpriteFont>();
            fontList.Add("Courier", Content.Load<SpriteFont>("Courier"));
            fontList.Add("Results", Content.Load<SpriteFont>("Results"));

        }

        //=============================================================
        // InitTextures
        // Desc: Loads the artwork for all grphics into ContentManager
        //=============================================================
        public Texture2D GetTexture(string id)
        {
            Debug.Assert(textureMap[id] != null);
            return textureMap[id];
        }

        //=============================================================
        // GetFonts
        // Desc: Returns the desired SpriteFont
        //=============================================================
        public SpriteFont GetFont(string id)
        {
            Debug.Assert(fontList[id] != null);
            return fontList[id];
        }

        //=============================================================
        // GetPlayerList
        // Desc: Returns the List
        //=============================================================
        public List<Player> GetPlayerList
        {
            get { return playerList; }
        }

        //=======================================================
        // Update
        // Desc: Updates user inputs and dynamic game objects 
        // for physics forces and collision. 
        //=======================================================
        public void Update(float deltaTime)
        {
            // Get controls from UI Singleton class
            foreach (Player player in playerList)
            {
                if (!player.Tank.RemoveFromGame)
                {
                    UpdateInput(player.Tank, player.PlayerIndexID);
                }
            }

            // Update Sprite positions
            foreach (Sprite sprt in spriteList)
            {
                sprt.Update(deltaTime);
            }

            UpdateCollisions();

			foreach (Player p in playerList)
			{
				p.Update(deltaTime);
			}

            currLevel.Update();

        }

        //=======================================================
        // UpdateCollisions
        // Desc: Updates sprite collisioins according to game
        //       rules
        //=======================================================
        public void UpdateCollisions()
        {
            // Resolve tank collisions
            for (int i = 0; i < spriteList.Count; ++i)
            {
                // Make sure this is a tank for first sprite and has not been marked as removed
                if (spriteList[i].GetType() != Type.GetType("Tank.TankSprite") ||
                    ((TankSprite)spriteList[i]).RemoveFromGame)
                {
                    continue;
                }

                // Tank to tank collisions
                for (int j = 0; j < spriteList.Count; ++j)
                {
                    if (j == i)
                        continue;

                    if (spriteList[j].GetType() == Type.GetType("Tank.TankSprite") && !((TankSprite)spriteList[j]).RemoveFromGame)
                    {
                        PhysicsBase.ResolveCircSprites((CircularSprite)spriteList[i], (CircularSprite)spriteList[j]);
                    }
                }
                // This tank's projectiles colliding with other tanks
                for (int j = 0; j < spriteList.Count; ++j)
                {
                    if (j == i)
                        continue;

                    if (spriteList[j].GetType() == Type.GetType("Tank.TankSprite") && !((TankSprite)spriteList[j]).RemoveFromGame)
                    {
                        UpdateBulletCollision( (TankSprite)spriteList[i], (TankSprite)spriteList[j]);
                    }
                }

                // Level Collisions
                List<Sprite> levelSprites = currLevel.GetLevelSprites();
                for (int j = 0; j < levelSprites.Count; ++j)
                { 
                    if( levelSprites[j].GetType() == Type.GetType("Tank.CircularSprite") )
                    {
                        PhysicsBase.ResolveCircSprites((CircularSprite)spriteList[i], (CircularSprite)levelSprites[j]);
                    }
                    else if (levelSprites[j].GetType().ToString() == "Tank.SquareSprite")
                    {
                        PhysicsBase.ResolveCircleToSquareSprites((CircularSprite)spriteList[i], (SquareSprite)levelSprites[j]);
                    }

                    // Test tank's bullets against level objects
                    UpdateBulletCollision(((TankSprite)spriteList[i]), levelSprites[j]);

                }

                // Collision with World Boundary
                PhysicsBase.ContainCircleSpriteInRect((CircularSprite)spriteList[i], currLevel.PlayableArea);
            }
        }

        //=======================================================
        // UpdateBulletCollision
        // Desc: Updates sprite collisions according to game
        //       rules
        //=======================================================
        public void UpdateBulletCollision(TankSprite tankShooter, TankSprite tankTarget)
        {
            int numProjectiles = tankShooter.NumProjectiles;
            for (int i = 0; i < numProjectiles; ++i)
            {
                Projectile projectile = tankShooter.GetProjectile(i);
                if (!projectile.IsLive)
                    continue;

                if (PhysicsBase.AreSpheresColliding(tankTarget.BoundSphere, projectile.BoundSphere))
                {
                    // Explode projectile
                    projectile.Explode(true, projectile.PType);
                    if (projectile.PType == Projectile_Type.PLASMA)
                        tankTarget.ApplyDamage(projectile.Damage + 20);
                    else
                        tankTarget.ApplyDamage(projectile.Damage);                    
                    tankShooter.IncreaseNumHits();

                    if (tankTarget.IsDead && tankTarget.JustDied)
                    {
                        tankShooter.IncreaseNumKills();
						SoundManager.Instance.PlaySound(SoundType.TANK_EXPLODE, true);
                    }
                }
            }
        }


        //=======================================================
        // UpdateBulletCollision - overloaded
        // Desc: Updates projectile collisions with level sprites
        //=======================================================
        public void UpdateBulletCollision(TankSprite tankShooter, Sprite targetSprite)
        {
            int numProjectiles = tankShooter.NumProjectiles;
            for (int i = 0; i < numProjectiles; ++i)
            {
                Projectile projectile = tankShooter.GetProjectile(i);
                // Don't check if projectile is dead
                if (!projectile.IsLive)
                {
                    continue;
                }

                if (targetSprite.GetType() == Type.GetType("Tank.CircularSprite"))
                {
                    if (PhysicsBase.AreSpheresColliding(((CircularSprite)projectile).BoundSphere, ((CircularSprite)targetSprite).BoundSphere))
                    {
                        // Explode projectile
                        projectile.Explode(false, projectile.PType);
                    }
                }
                else if (targetSprite.GetType() == Type.GetType("Tank.SquareSprite"))
                {
                    if (((CircularSprite)projectile).BoundSphere.Intersects(((SquareSprite)targetSprite).BoundBox))
                    {
                        // Explode projectile
                        projectile.Explode(false, projectile.PType);
                    }
                }
            }
        }

        //=============================================================
        // Draw 
        // Desc: Draw all world objects
        //=============================================================
        public void Draw()
        {
            //Draw level spites ***TJS
            currLevel.Draw(spriteBatch);

            // TODO: Draw out sprites
            for (int i = 0; i < spriteList.Count; ++i)
            {
                if (spriteList[i].GetType() == Type.GetType("Tank.TankSprite") && !((TankSprite)spriteList[i]).RemoveFromGame)
                {
                    spriteList[i].Draw(spriteBatch);
                }
            }

			//JAB - Player wasn't updating, so this may or may not be needed
			foreach (Player player in playerList)
			{
                if (!player.Tank.RemoveFromGame)
                {
                    player.Draw(spriteBatch);
                }
				
			}
        }

        //=============================================================
        // Draw 
        // Desc: TODO: Resets the world to play a level given the 
        // name of the level
        //=============================================================        
        private void ResetLevel(string levelName)
        {
            gameOver = false;
        }

        //=============================================================
        // Draw 
        // Desc: TODO: Resets the world to play a level given the 
        // name of the level
        //=============================================================  
        private void SetSpritePositions()
        {

        }


        //=============================================================
        // UpdateInput 
        // Desc: TODO: This functionality belongs in the UI class
        //=============================================================  
        private void UpdateInput(TankSprite tank, PlayerIndex indx)
        {
            KeyboardState currState = Keyboard.GetState();
            MouseState currMouseState = Mouse.GetState();
            float tankSpeed = 50.0f;
            
            //-----------------GamePad---------------------//
            if( Input.Instance.UsingGamePad )
            {
                const float ThumbStickTollerance = 0.01f;
                Vector2 dir = Input.Instance.GetLeftThumbStick(indx);
                if (dir.Length() > ThumbStickTollerance)
                {
                    Vector2 accel = new Vector2();
                    accel = tank.Direction * tankSpeed;
                    tank.ApplyAccel(accel);

                    dir.Normalize();
                    dir.Y *= -1;
                    tank.Rotate(dir);
                }

                dir = Input.Instance.GetRightThumbStick(indx);
                if (dir.Length() > ThumbStickTollerance)
                {
                    if (dir.X < 0 || (dir.X == 0 && dir.Y < 0))
                    {
                        tank.RotateTurret(false);
                    }
                    else
                    {
                        tank.RotateTurret(true);
                    }
                }

				if (Math.Abs(tank.Accel.Length()) > 0)
				{
					SoundManager.Instance.PlaySound(SoundType.TANK_ENGINE_1, indx);
					//SoundManager.Instance.PlaySound(SoundType.TANK_ENGINE_2);
					SoundManager.Instance.PlaySound(SoundType.TANK_ENGINE_3, indx);
				}
				else
				{
					SoundManager.Instance.PauseSound(SoundType.TANK_ENGINE_1, indx);
					//SoundManager.Instance.PauseSound(SoundType.TANK_ENGINE_2);
					SoundManager.Instance.PauseSound(SoundType.TANK_ENGINE_3, indx);
				}

                if (Input.Instance.DidRightTriggerJustGoDown(Buttons.RightTrigger, indx))
                {
                    tank.Fire();
                    return;
                }

                // LEEROOOOYYYYY JENKINS!
                if (Input.Instance.DidLeftTriggerJustGoDown(Buttons.LeftTrigger, indx))
                {
                    //SoundManager.Instance.PlaySound(SoundType.TANK_BOOST, indx);
					SoundManager.Instance.PlaySound(SoundType.TANK_ENGINE_2, indx);
                    return;
                }

                // NOS BOOSTER
                if (Input.Instance.IsLeftTriggerDown(Buttons.LeftTrigger, indx))
                {
                    //tank.SecondaryFire();

                    tank.ApplyAccel(2 * tank.Accel);

                    //tank.Accel *= 2;
                    return;
                }

				if (Input.Instance.DidLeftTriggerJustGoUp(Buttons.LeftTrigger, indx))
				{
					//SoundManager.Instance.PlaySound(SoundType.TANK_DECELERATE, indx);
					SoundManager.Instance.PauseSound(SoundType.TANK_ENGINE_2, indx);

					return;
				}



            }

            //-----------------Keyboard---------------------//
            if (Input.Instance.UsingKeyBoard && indx == PlayerIndex.One)
            {
                // Check for key states
                if (Input.Instance.IsKeyDown(Keys.Down))
                {
                    Vector2 accel = new Vector2();
                    accel = tank.Direction * tankSpeed;
                    tank.ApplyAccel(accel);
                    tank.Rotate(new Vector2(0, 1));
                }
                else if (Input.Instance.IsKeyDown(Keys.Up))
                {
                    Vector2 accel = new Vector2();
                    accel = tank.Direction * tankSpeed;
                    tank.ApplyAccel(accel);
                    tank.Rotate(new Vector2(0, -1));
                }
                else if (Input.Instance.IsKeyDown(Keys.Left))
                {
                    Vector2 accel = new Vector2();
                    accel = tank.Direction * tankSpeed;
                    tank.ApplyAccel(accel);
                    tank.Rotate(new Vector2(-1, 0));
                }
                else if (Input.Instance.IsKeyDown(Keys.Right))
                {
                    Vector2 accel = new Vector2();
                    accel = tank.Direction * tankSpeed;
                    tank.ApplyAccel(accel);
                    tank.Rotate(new Vector2(1, 0));
                }
				// Sound: Tank Engine/Movement sound. TODO: Add Speed Up/Slow Down Sound Effects.

                if (Math.Abs(tank.Accel.Length()) > 0)
				{
					SoundManager.Instance.PlaySound(SoundType.TANK_ENGINE_1, indx);
					//SoundManager.Instance.PlaySound(SoundType.TANK_ENGINE_2);
					SoundManager.Instance.PlaySound(SoundType.TANK_ENGINE_3, indx);
				}
				else
				{
					SoundManager.Instance.PauseSound(SoundType.TANK_ENGINE_1, indx);
					//SoundManager.Instance.PauseSound(SoundType.TANK_ENGINE_2);
					SoundManager.Instance.PauseSound(SoundType.TANK_ENGINE_3, indx);
				}


                if (Input.Instance.IsKeyDown(Keys.Q)) 
                {
                    tank.RotateBase(false);
                }

                else if (Input.Instance.IsKeyDown(Keys.E))
                {
                    tank.RotateBase(true);

                }

                if (Input.Instance.IsKeyDown(Keys.A))
                {
                    tank.RotateTurret(false);
                }

                else if (Input.Instance.IsKeyDown(Keys.D))
                {
                    tank.RotateTurret(true);
                }

                // FIRE!
                if (Input.Instance.DidKeyJustGoDown(Keys.Space))
                {
                    tank.Fire();
                    return;
                }

                if (Input.Instance.DidKeyJustGoDown(Keys.LeftAlt))
                {
                    tank.SecondaryFire();
                    return;
                }
            }

            

            //=================================================
            // Check for mouse states
            //=================================================
#if DEBUG_MODE
            //if (Input.Instance.DidMouseButtonJustGoDown())
            //{
            //    string debugStr = String.Format("Left Mouse Click, Position.x= {0}, Position.y = {1}", currMouseState.X, currMouseState.Y);
            //    Console.WriteLine(debugStr);
            //}

#endif // DEBUG_MODE
        }

        
        public Level CurrLevel
        {
            get
            {
                return currLevel;
            }
            set
            {
                currLevel = value;
            }
        }

		//============================================
		// Heads up Display
		//============================================
		public void InitHUD(List<Player> players)
		{
			hud = new HUD(spriteBatch);
		}
		public HUD Hud
		{
			get { return hud; }
		}
    }
}